#ifndef __MODULE_HEADER
#define __MODULE_HEADER

#include "socket_recv_buff.h"
#include "socket_send_buff.h"

#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <sys/select.h>
#include <time.h>

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <vector>
#include <utility>
#include <map>
#include <queue>
#include <stack>
#include <algorithm>

#define SELECT_TIMEOUT 		-3
#define SELECT_ERROR		-2
#define WRITE_ERROR			-1
#define REMOTE_CLOSE		0
#define SELECT_OK			1

typedef struct sockaddr SA;

const char *SERVER_IP 			= "127.0.0.1";
const int SERVER_PORT 			= 7726;
const int MAX_SEND_DATA_SIZE 	= 10100;
const int HEADER_SIZE			= 64;
const int FIELD_SIZE			= 16;
const int MAX_FILE_NAME_SIZE	= 100;
const int MAX_SRC_SIZE			= 10000;

void init_server_addr(sockaddr_in &server_addr, socklen_t &server_len) {
	memset(&server_addr, 0, sizeof(server_addr));
	server_addr.sin_family = AF_INET;
	inet_pton(AF_INET, SERVER_IP, &server_addr.sin_addr);
	server_addr.sin_port = htons(SERVER_PORT);
	server_len = sizeof(server_addr);
}

void init_client_addr(sockaddr_in &client_addr, socklen_t &client_len) {
	memset(&client_addr, 0, sizeof(client_addr));
	client_len = sizeof(client_addr);
}


int socket_connect(int &socket_fd, sockaddr_in &server_addr, socklen_t server_len) {
	socket_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	int res = connect(socket_fd, (const SA*)&server_addr, server_len);
	if (res == -1) {
		printf("connect ERROR\n");
		exit(0);
	}
	return socket_fd;
}

void parse_file_name(int fd, const char *file_name, char *oj, char *pro_id, 
					 char *lang, char *code_length, int &code_length__, char *src) {
	int i,j;
	memset(oj, 		0, sizeof(char) * FIELD_SIZE);
	memset(pro_id, 	0, sizeof(char) * FIELD_SIZE);
	memset(lang,   	0, sizeof(char) * FIELD_SIZE);
	memset(code_length, 0, sizeof(char) * FIELD_SIZE);
	memset(src,   	0, sizeof(char) * MAX_SRC_SIZE);

	for (i = 0, j = 0; true; i++, j++) {
		if (!isdigit(file_name[i])) 
			oj[j] = file_name[i];
		else {
			oj[j] = '\0';
			break;
		}
	}
	for (j = 0; true; j++, i++) {
		if (file_name[i] != '.')
			pro_id[j] = file_name[i];
		else {
			pro_id[j] = '\0';
			break;
		}
	}
	sprintf(lang, "G++");
	code_length__ = read(fd, src, MAX_SRC_SIZE);
		
	sprintf(code_length, "%d", code_length__);
}

ssize_t create_send_data(char *send_data, const char *oj, const char *pro_id,
						 const char *lang, const char *code_length, const int code_length__,
						 const char *src) {
	memset(send_data, 0, sizeof(char) * MAX_SEND_DATA_SIZE);
	sprintf(send_data, 				"%s", oj);
	sprintf(send_data+FIELD_SIZE, 	"%s", pro_id);
	sprintf(send_data+2*FIELD_SIZE,	"%s", lang);
	sprintf(send_data+3*FIELD_SIZE,	"%s", code_length);
	strncpy(send_data+4*FIELD_SIZE,	src, code_length__);
	return HEADER_SIZE + code_length__;
}

int select_read_process(int socket_fd, fd_set &all_read_set, fd_set &ready_read_set) {
	struct timeval tv = {15, 0};
	SockRecvBuff srb;
	while (true) {
		ready_read_set = all_read_set;
		int n = select(socket_fd+1, &ready_read_set, NULL, NULL, &tv);
		printf("select_read_process返回值：%d\n", n);
		if (n == -1) 	return SELECT_ERROR;
		if (n == 0) 	return SELECT_TIMEOUT;
		if (FD_ISSET(socket_fd, &ready_read_set)) {
			ssize_t res = srb.read_data(socket_fd);
			if (res == 0)  	return REMOTE_CLOSE;
			if (srb.finish_body()) {
				//printf("index=%d\n", srb.index);
				write(1, srb.buff, srb.index), printf("\n\n");
				break;
			}
		}
	}
	return SELECT_OK;
}

int select_write_process(int socket_fd, fd_set &all_write_set, fd_set &ready_write_set,
						 const char *send_data, const ssize_t send_data_size) {
	struct timeval tv = {15, 0};
	SocketSendBuff ssb(send_data, send_data_size);
	while (true) {
		ready_write_set = all_write_set;
		int n = select(socket_fd+1, NULL, &ready_write_set, NULL, &tv);
		printf("select_write_process返回值：%d\n", n);
		if (n == -1) return SELECT_ERROR;
		if (n == 0)  return SELECT_TIMEOUT;
		if (FD_ISSET(socket_fd, &ready_write_set)) {
			ssize_t res = ssb.write_data(socket_fd);
			printf("发送字节数: %d\n", res);
			if (res == -1) return WRITE_ERROR;
			if (ssb.finish()) break;
		}
	}
	return SELECT_OK;
}

// 单个用户，人为控制
int one_socket_block_module(int socket_fd, sockaddr_in &server_addr, socklen_t &server_len,
		sockaddr_in &client_addr, socklen_t &client_len) {
	
	char send_data[MAX_SEND_DATA_SIZE];
	ssize_t send_data_size;
	char file_name[MAX_FILE_NAME_SIZE];

	char oj[FIELD_SIZE];
	char pro_id[FIELD_SIZE];
	char lang[FIELD_SIZE];
	char code_length[FIELD_SIZE];
	int code_length__;
	char src[MAX_SRC_SIZE];

	fd_set all_read_set, all_write_set, ready_read_set, ready_write_set;

	FD_ZERO(&all_read_set);
	FD_ZERO(&all_write_set);
	FD_SET(socket_fd, &all_read_set);
	FD_SET(socket_fd, &all_write_set);

	int try_cnt = 30;
	while (true) {
		printf("input source file name: "), scanf("%s", file_name);
		//sprintf(file_name, "poj1000.cpp");
		int fd = open(file_name, O_RDONLY, O_EXCL);
		if (fd == -1) {
			printf("can not open file\n");
			continue;
		}
		parse_file_name(fd, file_name, oj, pro_id, 
						lang, code_length, code_length__, src);
		send_data_size = create_send_data(send_data, oj, pro_id, lang,
										  code_length, code_length__, src);
		////////////////////////////////////////////
		//printf("%s\n%s\n%s\n%s\n%s\n",
		//		oj, pro_id, lang, code_length, src);
		//write(1, send_data, send_data_size);
		////////////////////////////////////////////
		
		// 多次发送直到发送完整
		int write_res = select_write_process(socket_fd, all_write_set, ready_write_set, 
									   send_data, send_data_size);
		// select接收，设置超时，直到接收完整或者超时返回
		int read_res = select_read_process(socket_fd, all_read_set, ready_read_set);
	}
	return 0;
}

#endif // __MODULE_HEADER
